package com.insight.common.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.*;

/**
 * MultipartFile 工具类，支持 File 与 InputStream 转 MultipartFile
 */
@Slf4j
public class MultipartFileUtil {

    /**
     * 将 File 转换为 MultipartFile
     *
     * @param file        源文件
     * @param fileName    文件名，空则取 file.getName()
     * @param contentType 文件类型（MIME）
     * @return MultipartFile 对象
     */
    public static MultipartFile fileToMultipartFile(File file, String fileName, String contentType) {
        if (StringUtils.isBlank(fileName)) {
            fileName = file.getName();
        }
        FileItem fileItem = createFileItem(file, fileName, contentType);
        return new CommonsMultipartFile(fileItem);
    }

    /**
     * 创建 FileItem 并将 File 内容写入 FileItem 流
     * 采用 try-with-resources 确保流关闭，异常时记录日志
     *
     * @param file        源文件
     * @param fileName    文件名
     * @param contentType 文件类型
     * @return FileItem
     */
    private static FileItem createFileItem(File file, String fileName, String contentType) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem(fileName, contentType, true, fileName);
        byte[] buffer = new byte[8192];
        try (FileInputStream fis = new FileInputStream(file);
             OutputStream os = item.getOutputStream()) {
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            log.error("读取文件或写入流出错", e);
        }
        return item;
    }

    /**
     * 将 InputStream 转换为 MultipartFile
     *
     * @param fileName    文件名
     * @param contentType 文件类型（MIME）
     * @param inputStream 输入流，调用后会被关闭
     * @return MultipartFile 对象
     */
    public static MultipartFile inputStreamToMultipartFile(String fileName, String contentType, InputStream inputStream) {
        FileItem fileItem = createFileItemFromInputStream(inputStream, fileName, contentType);
        return new CommonsMultipartFile(fileItem);
    }

    /**
     * 创建 FileItem 并将 InputStream 内容写入 FileItem 流
     * 采用 try-with-resources 确保流关闭，异常时记录日志
     * 注意：该方法会关闭传入的 inputStream，如果外部还需要使用，请先备份或另行处理
     *
     * @param inputStream 输入流
     * @param fileName    文件名
     * @param contentType 文件类型
     * @return FileItem
     */
    private static FileItem createFileItemFromInputStream(InputStream inputStream, String fileName, String contentType) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem(fileName, contentType, true, fileName);
        byte[] buffer = new byte[8192];
        try (InputStream is = inputStream;
             OutputStream os = item.getOutputStream()) {
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            log.error("读取输入流或写入流出错", e);
        }
        return item;
    }
}
